package com.imooc.course.server.service.impl;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.imooc.course.server.dao.ResourceDao;
import com.imooc.course.server.dao.my.MyResourceDao;
import com.imooc.course.server.dto.LoginUserDto;
import com.imooc.course.server.dto.ResourceDto;
import com.imooc.course.server.dto.PageDto;
import com.imooc.course.server.entity.Resource;
import com.imooc.course.server.entity.ResourceExample;
import com.imooc.course.server.service.ResourceService;
import com.imooc.course.server.utils.CopyUtil;
import com.imooc.course.server.utils.UuidUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service("resourceService")
public class ResourceServiceImpl implements ResourceService {

    private static final Logger log = LoggerFactory.getLogger(ResourceServiceImpl.class);

    @javax.annotation.Resource(name = "resourceDao")
    private ResourceDao resourceDao;

    @javax.annotation.Resource(name = "myResourceDao")
    private MyResourceDao myResourceDao;


    /**
     * 资源树的展示
     */
    @Override
    public List<ResourceDto> getList() {
        ResourceExample resourceExample = new ResourceExample();
        resourceExample.setOrderByClause("id asc");
        List<Resource> resourceList = resourceDao.selectByExample(resourceExample);
        List<ResourceDto> resourceDtoList = CopyUtil.copyList(resourceList, ResourceDto.class);
        return resourceDtoList;
    }

    /**
     * 资源树的展示，来自老师的实现思路，
     * 适用于除zTree以外，不能自动识别id与parentId展示树形结构的前端插件。
     */
    @Override
    public List<ResourceDto> loadTree() {
        ResourceExample resourceExample = new ResourceExample();
        resourceExample.setOrderByClause("id asc");
        List<Resource> resourceList = resourceDao.selectByExample(resourceExample);
        List<ResourceDto> resourceDtoList = CopyUtil.copyList(resourceList, ResourceDto.class);
        //有pId就是有父级的，pId为null的就是顶级父级。
        this.convertListToTree(resourceDtoList);
        return resourceDtoList;
    }

    private void convertListToTree(List<ResourceDto> list) {
        for (int i = list.size() - 1; i >= 0; i--) {
            // 当前要移动的记录
            ResourceDto child = list.get(i);

            // 如果当前节点没有父节点，则不用往下了
            if (StringUtils.isEmpty(child.getParent())) {
                continue;
            }
            // 查找父节点
            for (int j = i - 1; j >= 0; j--) {
                ResourceDto parent = list.get(j);
                if (child.getParent().equals(parent.getId())) {
                    if (CollectionUtils.isEmpty(parent.getChildren())) {
                        parent.setChildren(new ArrayList<>());
                    }
                    // 添加到最前面，否则会变成倒序，因为循环是从后往前循环的
                    parent.getChildren().add(0, child);

                    // 子节点找到父节点后，删除列表中的子节点
                    list.remove(child);
                    break;
                }
            }
        }
    }

    /**
     * 列表查询
     * @param pageDto
     */
    @Override
    public void getList(PageDto pageDto) {
        PageHelper.startPage(pageDto.getPage(),pageDto.getSize());

        ResourceExample resourceExample = new ResourceExample();
        List<Resource> resourceList = resourceDao.selectByExample(resourceExample);

        PageInfo<Resource> resourcePageInfo = new PageInfo<>(resourceList);
        pageDto.setTotal(resourcePageInfo.getTotal());

        List<ResourceDto> resourceDtoList = CopyUtil.copyList(resourceList, ResourceDto.class);

        pageDto.setList(resourceDtoList);
    }

    /**
     * 保存资源树
     * @param resourceDtoList
     */
    @Transactional
    @Override
    public void save(List<ResourceDto> resourceDtoList) {
        List<Resource> list = new ArrayList<Resource>();
        this.convertTreeToList(resourceDtoList, list, new HashMap<String, String>());
        resourceDao.deleteByExample(null);
        myResourceDao.batchInsert(list);
    }

    private void convertTreeToList(List<ResourceDto> sourcesList, List<Resource> list, Map<String, String> idMap) {
        for (int i = sourcesList.size()-1; i >= 0; i--) {
            ResourceDto resourceDto = sourcesList.get(i);
            if (!CollectionUtils.isEmpty(resourceDto.getChildren())) {
                for (int j = 0; j < resourceDto.getChildren().size(); j++) {
                    ResourceDto dto = resourceDto.getChildren().get(j);
                    idMap.put(dto.getId(), resourceDto.getId());
                }
                convertTreeToList(resourceDto.getChildren(), list, idMap);
            }
            resourceDto.setParent(idMap.get(resourceDto.getId()));
            list.add(0,CopyUtil.copy(resourceDto,Resource.class));
        }
    }

    /**
     * 保存资源树，来自老师的的第二种实现
     * @param resourceJson
     */
    @Transactional
    @Override
    public void save(String resourceJson) {
        List<Resource> list = new ArrayList<Resource>();
        // 我的实现是在controller层就将json脚本转换为list再传入service层。
        // 老师的思路是controller层不作转换，直接将前端的json脚本传到这里再转换也是可以的。
        List<ResourceDto> resourceDtoList = JSON.parseArray(resourceJson, ResourceDto.class);
        for (ResourceDto resourceDto : resourceDtoList) {
            resourceDto.setParent("");
            list.add(CopyUtil.copy(resourceDto, Resource.class));
            this.convertTreeToList(resourceDto,list);
        }
        resourceDao.deleteByExample(null);
        myResourceDao.batchInsert(list);
    }

    private void convertTreeToList(ResourceDto dto, List<Resource> list) {
        if (!CollectionUtils.isEmpty(dto.getChildren())) {
            for (ResourceDto dtoChild : dto.getChildren()) {
                dtoChild.setParent(dto.getId());
                list.add(CopyUtil.copy(dtoChild, Resource.class));
                convertTreeToList(dtoChild, list);
            }
        }
    }

    private void updateResource(Resource copy) {
        resourceDao.updateByPrimaryKeySelective(copy);
    }

    private void addResource(Resource copy) {
        copy.setId(UuidUtil.getShortUuid());
        resourceDao.insertSelective(copy);
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void delete(String id) {
        resourceDao.deleteByPrimaryKey(id);
    }

    @Override
    public List<ResourceDto> readUserAuth(LoginUserDto loginUserDto) {
        List<Resource> list = myResourceDao.selectByUserId(loginUserDto.getId());
        return CopyUtil.copyList(list,ResourceDto.class);
    }
}
